import logging
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

from ..core.data_loader import MYSQL_AVAILABLE, ORACLE_AVAILABLE
from ..utils.logger import logger


class DatabaseConfigDialog(tk.Toplevel):
    """数据库连接配置对话框"""

    def __init__(self, parent, existing_config=None):
        """初始化
        Args:
            parent: 父窗口
            existing_config: 现有配置，用于回显
        """
        super().__init__(parent)
        self.title("数据库连接配置")
        self.geometry("800x500")
        self.resizable(False, False)

        # 设置模态
        self.transient(parent)
        self.grab_set()

        self.result = None
        self.existing_config = existing_config
        self._init_ui()

        # 如果有现有配置，进行回显
        if existing_config:
            self._load_existing_config()

        # 使用 after 方法延迟执行居中显示
        self.after(10, lambda: parent.app.center_dialog(self))

    def _init_ui(self):
        # 按钮区域
        btn_frame = ttk.Frame(self)  # 改为直接附加到对话框
        btn_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=10, padx=10)

        # 按钮靠右对齐
        btn_container = ttk.Frame(btn_frame)
        btn_container.pack(side=tk.RIGHT)

        ttk.Button(btn_container, text="测试连接", command=self._test_connection).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(btn_container, text="确定", command=self._on_ok).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(btn_container, text="取消", command=self._on_cancel).pack(
            side=tk.LEFT
        )

        # 主布局框架
        main_frame = ttk.Frame(self, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 左侧框架 - 数据库类型和连接信息
        left_frame = ttk.Frame(main_frame)
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))

        # 数据库类型
        type_frame = ttk.LabelFrame(left_frame, text="数据库类型", padding="5")
        type_frame.pack(fill=tk.X, pady=(0, 10))

        self.type_combo = ttk.Combobox(type_frame, values=["MySQL", "Oracle"])
        self.type_combo.pack(fill=tk.X)
        self.type_combo.set("MySQL")
        self.type_combo.bind("<<ComboboxSelected>>", self._on_type_changed)

        # Oracle配置框架
        self.oracle_frame = ttk.LabelFrame(
            left_frame, text="Oracle连接模式", padding="5"
        )

        # 连接模式选择 - 修改默认值为 thin
        self.oracle_mode = tk.StringVar(value="thin")
        ttk.Radiobutton(
            self.oracle_frame,
            text="Thick模式(需要客户端)",
            variable=self.oracle_mode,
            value="thick",
            command=self._on_oracle_mode_changed,
        ).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(
            self.oracle_frame,
            text="Thin模式(无需客户端)",
            variable=self.oracle_mode,
            value="thin",
            command=self._on_oracle_mode_changed,
        ).pack(side=tk.LEFT)

        # Oracle客户端目录配置
        self.oracle_client_frame = ttk.LabelFrame(
            left_frame, text="Oracle客户端配置", padding="5"
        )

        client_frame = ttk.Frame(self.oracle_client_frame)
        client_frame.pack(fill=tk.X, pady=5)

        self.oracle_client_input = ttk.Entry(client_frame)
        self.oracle_client_input.pack(side=tk.LEFT, fill=tk.X, expand=True)

        self.oracle_client_btn = ttk.Button(
            client_frame,
            text="选择目录",
            command=self._select_oracle_client_dir,
        )
        self.oracle_client_btn.pack(side=tk.LEFT, padx=(5, 0))

        # 初始隐藏Oracle相关配置
        if self.type_combo.get().lower() != "oracle":
            self.oracle_frame.pack_forget()
            self.oracle_client_frame.pack_forget()
        else:
            self.oracle_frame.pack(fill=tk.X, pady=(0, 5))

        # 连接信息分组
        conn_frame = ttk.LabelFrame(left_frame, text="连接信息", padding="5")
        conn_frame.pack(fill=tk.BOTH, expand=True)

        # 使用Grid布局连接信息
        ttk.Label(conn_frame, text="主机:").grid(row=0, column=0, sticky="w", pady=2)
        self.host_input = ttk.Entry(conn_frame)
        self.host_input.grid(row=0, column=1, sticky="ew", padx=5, pady=2)

        ttk.Label(conn_frame, text="端口:").grid(row=1, column=0, sticky="w", pady=2)
        self.port_input = ttk.Entry(conn_frame)
        self.port_input.grid(row=1, column=1, sticky="ew", padx=5, pady=2)

        ttk.Label(conn_frame, text="数据库:").grid(row=2, column=0, sticky="w", pady=2)
        self.db_input = ttk.Entry(conn_frame)
        self.db_input.grid(row=2, column=1, sticky="ew", padx=5, pady=2)

        ttk.Label(conn_frame, text="用户名:").grid(row=3, column=0, sticky="w", pady=2)
        self.user_input = ttk.Entry(conn_frame)
        self.user_input.grid(row=3, column=1, sticky="ew", padx=5, pady=2)

        ttk.Label(conn_frame, text="密码:").grid(row=4, column=0, sticky="w", pady=2)
        self.pass_input = ttk.Entry(conn_frame, show="*")
        self.pass_input.grid(row=4, column=1, sticky="ew", padx=5, pady=2)

        conn_frame.grid_columnconfigure(1, weight=1)

        # 右侧框架 - SQL查询
        right_frame = ttk.LabelFrame(main_frame, text="SQL查询", padding="5")
        right_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 0))

        self.sql_input = tk.Text(right_frame, height=15)
        self.sql_input.pack(fill=tk.BOTH, expand=True)

    def _on_ok(self):
        """确定按钮处理"""
        try:
            # 获取数据库类型
            db_type = self.type_combo.get().lower()

            # 检查必要的驱动是否已安装
            if db_type == "mysql" and not MYSQL_AVAILABLE:
                raise ImportError("未安装 PyMySQL 模块，请先安装：pip install PyMySQL")
            elif db_type == "oracle" and not ORACLE_AVAILABLE:
                raise ImportError(
                    "未安装 oracledb 模块，请按照以下步骤安装：\n\n"
                    "1. 安装 oracledb：\n"
                    "   pip install oracledb\n\n"
                    "2. 下载Oracle客户端：\n"
                    "   - 访问：https://www.oracle.com/database/technologies/instant-client/downloads.html\n"
                    "   - 选择对应的操作系统和版本\n"
                    "   - 下载 Basic Package\n\n"
                    "3. 安装步骤：\n"
                    "   - 解压下载的文件到本地目录（如 D:\\oracle_client）\n"
                    "   - 将解压目录添加到系统环境变量 PATH\n"
                    "   - 设置环境变量 ORACLE_CLIENT_PATH 为解压目录\n\n"
                    "4. 重启应用\n\n"
                    "注意：确保下载的版本（32位/64位）与Python版本匹配"
                )

            # 收集配置信息
            self.result = {
                "type": db_type,
                "path": self.sql_input.get("1.0", tk.END).strip(),
                "db_config": {
                    "type": db_type,
                    "host": self.host_input.get().strip(),
                    "port": int(self.port_input.get().strip()),
                    "database": self.db_input.get().strip(),
                    "username": self.user_input.get().strip(),
                    "password": self.pass_input.get().strip(),
                },
            }

            # 如果是Oracle，添加相关配置
            if db_type == "oracle":
                self.result["db_config"]["mode"] = self.oracle_mode.get()
                if self.oracle_mode.get() == "thick":
                    oracle_client_dir = self.oracle_client_input.get().strip()
                    if oracle_client_dir:
                        self.result["db_config"][
                            "oracle_client_dir"
                        ] = oracle_client_dir

            self.destroy()

        except Exception as e:
            logger.error(f"保存数据库配置失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"保存失败: {str(e)}")

    def _on_cancel(self):
        self.destroy()

    def _test_connection(self):
        """测试数据库连接"""
        try:
            # 获取数据库类型
            db_type = self.type_combo.get().lower()

            # 检查必要的驱动是否已安装
            if db_type == "mysql" and not MYSQL_AVAILABLE:
                raise ImportError("未安装 PyMySQL 模块，请先安装：pip install PyMySQL")
            elif db_type == "oracle" and not ORACLE_AVAILABLE:
                raise ImportError(
                    "未安装 oracledb 模块，请先安装：pip install oracledb"
                )

            # 收集连接信息
            connection_info = {
                "host": self.host_input.get().strip(),
                "port": self.port_input.get().strip(),
                "database": self.db_input.get().strip(),
                "user": self.user_input.get().strip(),
                "password": self.pass_input.get().strip(),
            }

            # 验证所有必填字段
            if not all(connection_info.values()):
                raise ValueError("请填写所有连接信息")

            # 尝试连接数据库
            if db_type == "mysql":
                import pymysql

                conn = pymysql.connect(
                    host=connection_info["host"],
                    port=int(connection_info["port"]),
                    user=connection_info["user"],
                    password=connection_info["password"],
                    database=connection_info["database"],
                    connect_timeout=5,
                )
                conn.close()
            elif db_type == "oracle":
                import oracledb

                # 根据连接模式处理
                if self.oracle_mode.get() == "thick":
                    # 获取Oracle客户端目录
                    oracle_client_dir = self.oracle_client_input.get().strip()
                    if oracle_client_dir:
                        # 设置Oracle客户端目录
                        try:
                            oracledb.init_oracle_client(lib_dir=oracle_client_dir)
                        except Exception as e:
                            if (
                                "OracleClient library has already been initialized"
                                not in str(e)
                            ):
                                raise Exception(f"Oracle客户端初始化失败: {str(e)}")

                # 构建Oracle连接字符串
                dsn = (
                    f"{connection_info['host']}:{connection_info['port']}"
                    f"/{connection_info['database']}"
                )

                # 根据模式创建连接
                if self.oracle_mode.get() == "thin":
                    conn = oracledb.connect(
                        user=connection_info["user"],
                        password=connection_info["password"],
                        dsn=dsn,
                        config_dir=None,
                        thin=True,  # 使用thin模式
                    )
                else:
                    conn = oracledb.connect(
                        user=connection_info["user"],
                        password=connection_info["password"],
                        dsn=dsn,
                        config_dir=None,
                    )
                conn.close()

            messagebox.showinfo("成功", "数据库连接测试成功！")
            logger.info(
                f"数据库连接测试成功: {db_type}@{connection_info['host']}:{connection_info['port']}"
            )

        except ImportError as e:
            messagebox.showerror("错误", str(e))
        except ValueError as e:
            messagebox.showerror("错误", str(e))
        except Exception as e:
            error_msg = str(e)
            if db_type == "oracle" and "DPI-1047" in error_msg:
                error_msg = (
                    "Oracle客户端未正确配置，请检查：\n"
                    "1. 是否已下载并安装Oracle Instant Client\n"
                    "2. 是否已将Oracle客户端目录添加到系统环境变量PATH\n"
                    "3. 是否已设置ORACLE_CLIENT_PATH环境变量"
                )
            logger.error(f"数据库连接测试失败: {error_msg}", exc_info=True)
            messagebox.showerror("错误", f"连接失败: {error_msg}")

    def _on_type_changed(self, event):
        """数据库类型变更处理"""
        if self.type_combo.get().lower() == "oracle":
            # 显示Oracle连接模式选择框架
            self.oracle_frame.pack(fill=tk.X, pady=5, after=self.type_combo)

            # 如果是thick模式，显示客户端配置框架
            if self.oracle_mode.get() == "thick":
                self.oracle_client_frame.pack(
                    fill=tk.X, pady=5, after=self.oracle_frame
                )

            # 设置默认端口
            if not self.port_input.get():
                self.port_input.delete(0, tk.END)
                self.port_input.insert(0, "1521")

            # 尝试从环境变量获取Oracle客户端目录
            oracle_client_path = os.environ.get("ORACLE_CLIENT_PATH", "")
            if oracle_client_path:
                self.oracle_client_input.delete(0, tk.END)
                self.oracle_client_input.insert(0, oracle_client_path)
        else:
            # 隐藏Oracle相关配置
            self.oracle_frame.pack_forget()
            self.oracle_client_frame.pack_forget()

            # 设置默认端口
            if not self.port_input.get():
                self.port_input.delete(0, tk.END)
                self.port_input.insert(0, "3306")

    def _select_oracle_client_dir(self):
        """选择Oracle客户端目录"""
        directory = filedialog.askdirectory(
            title="选择Oracle客户端目录", mustexist=True
        )
        if directory:
            self.oracle_client_input.delete(0, tk.END)
            self.oracle_client_input.insert(0, directory)

    def _on_oracle_mode_changed(self):
        """Oracle连接模式变更处理"""
        if self.oracle_mode.get() == "thin":
            self.oracle_client_frame.pack_forget()
        else:
            self.oracle_client_frame.pack(fill=tk.X, pady=5)

    def _load_existing_config(self):
        """加载现有配置"""
        try:
            if self.existing_config:
                # 设置数据库类型
                db_type = self.existing_config["db_config"].get("type", "").lower()
                if db_type:
                    self.type_combo.set(db_type.capitalize())

                # 设置主机名
                self.host_input.insert(
                    0, self.existing_config["db_config"].get("host", "")
                )
                # 设置端口
                self.port_input.insert(
                    0, str(self.existing_config["db_config"].get("port", ""))
                )
                # 设置数据库名
                self.db_input.insert(
                    0, self.existing_config["db_config"].get("database", "")
                )
                # 设置用户名
                self.user_input.insert(
                    0, self.existing_config["db_config"].get("username", "")
                )
                # 设置密码
                self.pass_input.insert(
                    0, self.existing_config["db_config"].get("password", "")
                )
                # 设置SQL语句
                self.sql_input.insert("1.0", self.existing_config.get("path", ""))

                # 如果是Oracle，设置连接模式和客户端目录
                if db_type == "oracle":
                    self.oracle_mode.set(
                        self.existing_config["db_config"].get("mode", "thin")
                    )
                    if "oracle_client_dir" in self.existing_config["db_config"]:
                        self.oracle_client_input.insert(
                            0, self.existing_config["db_config"]["oracle_client_dir"]
                        )
                    # 触发类型改变事件以显示Oracle相关配置
                    self._on_type_changed(None)
                    # 触发模式改变事件以显示/隐藏客户端配置
                    self._on_oracle_mode_changed()

                logger.info(f"成功加载数据库配置: {self.existing_config}")

        except Exception as e:
            logger.error(f"加载现有配置失败: {str(e)}", exc_info=True)
